package itdep.common.services.impl;

import itdep.common.services.Pagination;
import org.springframework.beans.support.MutableSortDefinition;
import org.springframework.beans.support.SortDefinition;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Ivan Khalopik
 * @version $Revision: 4 $ $Date: 2010-06-10 13:13:16 +0000 (Thu, 10 Jun 2010) $
 */
public class PaginationBuilder implements Pagination {
	private int start;
	private int count;
	private SortDefinition[] sortDefinitions;

	private int from;
	private int to;
	private int page;
	private int size = -1;
	private final List<SortDefinition> sorts = new ArrayList<SortDefinition>();

	private boolean modified = true;

	public int getStart() {
		lazyBuild();
		return start;
	}

	public int getCount() {
		lazyBuild();
		return count;
	}

	public SortDefinition[] getSortDefinitions() {
		lazyBuild();
		return sortDefinitions;
	}

	public PaginationBuilder start(final int start) {
		this.from = start;
		return modify();
	}

	public PaginationBuilder end(final int end) {
		if (page > 0 || size > 0) {
			throw new UnsupportedOperationException("page or size attributes already exists");
		}
		this.to = end;
		return modify();
	}

	public PaginationBuilder count(final int count) {
		return size(count);
	}

	public PaginationBuilder size(final int size) {
		if (to > 0) {
			throw new UnsupportedOperationException("to attribute already exists");
		}
		this.size = size;
		return modify();
	}

	public PaginationBuilder page(final int page) {
		if (to > 0) {
			throw new UnsupportedOperationException("to attribute already exists");
		}
		this.page = page;
		return modify();
	}

	public PaginationBuilder sort(final String property) {
		return sort(property, false);
	}

	public PaginationBuilder sort(final String property, final boolean ascending) {
		return sort(property, ascending, false);
	}

	public PaginationBuilder sort(final String property, final boolean ascending, final boolean ignoreCase) {
		sorts.add(new MutableSortDefinition(property, ignoreCase, ascending));
		return modify();
	}

	public PaginationBuilder unsorted() {
		sorts.clear();
		return modify();
	}

	private PaginationBuilder modify() {
		this.modified = true;
		return this;
	}

	private void lazyBuild() {
		if (modified) {
			if (page > 0 && size >= 0) {
				start = from + (page - 1) * size;
				count = size;
			} else if (to > 0 && to >= from) {
				start = from;
				count = to - from;
			} else {
				start = from;
				count = size >= 0 ? size : -1;
			}
			sortDefinitions = sorts.toArray(new SortDefinition[sorts.size()]);
			modified = false;
		}
	}

	public static PaginationBuilder create() {
		return new PaginationBuilder();
	}
}
